package com.ibo.htlivecamera;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.FragmentTransaction;
import android.text.InputType;
import android.text.method.DigitsKeyListener;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.ibo.htlivecamera.app.Constants;
import com.ibo.htlivecamera.app.MyApplication;
import com.ibo.htlivecamera.base.BaseActivity;
import com.ibo.htlivecamera.base.BaseFragment;
import com.ibo.htlivecamera.launcher.AppsActivity;
import com.ibo.htlivecamera.player.PlayerFragment;
import com.ibo.htlivecamera.player.RtspPlayerFragment;
import com.ibo.htlivecamera.service.ServiceManager;
import com.ibo.htlivecamera.socket.SimpleEvent;
import com.daniulive.smartpublisher.PublishUtil;
import com.ibo.htlivecamera.util.Util;
import com.ibo.htlivecamera.view.UpdateDialog;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.xutils.view.annotation.Event;
import org.xutils.view.annotation.ViewInject;

import java.io.IOException;

public class MainActivity extends BaseActivity implements SurfaceHolder.Callback, Camera.PreviewCallback {


    static {
        System.loadLibrary("SmartPlayer");
//        System.loadLibrary("UVC");
    }

    public static final int CODE_RECONNECTING = 757;
    private BaseFragment currentFragment;
    private String currentCameraName;

    @ViewInject(R.id.status_tv)
    TextView statusTv;
    @ViewInject(R.id.status_view)
    View statusView;
    private String lastPlayingUrl = "";

    @ViewInject(R.id.status_parent)
    ViewGroup statusParent;
    @ViewInject(R.id.btns_parent)
    ViewGroup btnsParent;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);    //屏幕常亮
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        hideBottomUIMenu();
        setContentView(R.layout.activity_main);

        changeStatusView(0, "正在连接...");

        EventBus.getDefault().register(this);

        initCameara();

        initSocketService();

        if (Constants.HOST.trim().isEmpty()) {
            showInputIpDialog();
        }
    }

    @Event({R.id.all_apps, R.id.setting})
    private void onBottomControlClick(View v) {
        switch (v.getId()) {
            case R.id.all_apps:
                startActivity(new Intent(this, AppsActivity.class));
                break;
            case R.id.setting:
                startActivity(new Intent(Settings.ACTION_SETTINGS));
                break;
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onSubscribe(SimpleEvent event) {
        switch (event.getCommand()) {
            case SimpleEvent.SHOW_ACTIVITY:
                System.out.println("#########  SHOW_ACTIVITY  ");
                ServiceManager.moveToFront();
                break;
            case SimpleEvent.VOLUME:
                System.out.println("##### VOLUME " + event.getParam());
                Util.controlVolume(Integer.parseInt(event.getParam()));
                break;
            case SimpleEvent.CONNECTED:
                log("CONNECTED  ");
                reCaptureCamera();

                changeStatusView(1, "已连接");
                break;
            case SimpleEvent.DISCONNECTED:
                log("DISCONNECTED");
                reCaptureCamera();

                changeStatusView(2, "已断开");
                stopPlay();
                stopPush();
                break;
            case SimpleEvent.START_PUSH:
                log("START_PUSH  " + event.getParam());
                stopPlay();
                startPush(event.getParam());
                changeStatusView(2, "视频广播中...");

                break;
            case SimpleEvent.STOP_PUSH:
                log("STOP_PUSH  " + event.getParam());
                stopPush();
                showName();
                break;
            case SimpleEvent.SET_NAME:
                log("SET_NAME  " + event.getParam());
                setName(event.getParam());
                break;
            case CODE_RECONNECTING:
                changeStatusView(0, "正在重连...");
                break;
            case SimpleEvent.SET_RATE:
                onSetRate(event.getParam());
                break;
            case SimpleEvent.CAMERA_ROTATE:
                onCameraRotate(event.getParam());
                break;
            case SimpleEvent.CAMERA_ZOOM:
                onCameraZoom(event.getParam());
                break;
            case SimpleEvent.START_PLAY:
                changeStatusView(1, "视频拉流中");
                startPlay(event.getParam());
                break;
            case SimpleEvent.STOP_PLAY:
                stopPlay();
                showName();
                break;
            case SimpleEvent.UPDATE:
                UpdateDialog updateDialog = new UpdateDialog(this);
                updateDialog.show();
                updateDialog.startDownload(event.getParam());
                break;
            case SimpleEvent.RECAPTURE_CAMERA:
                reCaptureCamera();
                break;
        }
    }

    private void reCaptureCamera() {
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.startPreview();
        }
    }


    private void reconnectIp() {
        ServiceManager.stopService(this);
        initSocketService();
    }


    private void initCameara() {
        System.out.println("######   initCameara");

        publishUtil = PublishUtil.getInstance(getApplicationContext());
        mSurfaceView = (SurfaceView) this.findViewById(R.id.surface);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(this);
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        //自动聚焦变量回调
        myAutoFocusCallback = new Camera.AutoFocusCallback() {
            public void onAutoFocus(boolean success, Camera camera) {

            }
        };

        currentCameraType = FRONT;
        if (mCamera == null) {
            mCamera = openCamera(currentCameraType);
        }
    }

    /**
     * 隐藏虚拟按键，并全屏
     */
    protected void hideBottomUIMenu() {
        if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) {
            View v = getWindow().getDecorView();
            v.setSystemUiVisibility(View.GONE);
        } else if (Build.VERSION.SDK_INT >= 19) {
            View decorView = getWindow().getDecorView();
            int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
            decorView.setSystemUiVisibility(uiOptions);
        }
    }

    private void initSocketService() {
        ServiceManager.startUpService(this);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == 17) {
            showInputIpDialog();
        }
        return super.onKeyDown(keyCode, event);
    }

    private void showInputIpDialog() {
        //192.168.0.35
        final EditText inputServer = new EditText(this);

        inputServer.setInputType(InputType.TYPE_CLASS_NUMBER);
        inputServer.setKeyListener(DigitsKeyListener.getInstance("0123456789."));
        inputServer.setText(Constants.HOST);
        inputServer.setSelection(Constants.HOST.length());
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("输入IP").setIcon(android.R.drawable.ic_dialog_info).setView(inputServer)
                .setNegativeButton("取消", (dialog, which) -> dialog.dismiss());
        builder.setPositiveButton("确定", (dialog, which) -> {
            String text = inputServer.getText().toString();
            MyApplication.getInstance().setIp(text);
            reconnectIp();
        });
        builder.show();
    }


    /**
     * 隐藏输入软键盘
     *
     * @param view
     */
    private void hideInputManager(View view) {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        if (view != null && imm != null) {
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);  //强制隐藏
        }
    }


    private void onCameraZoom(String param) {
        if (mCamera != null) {
            int action = Integer.parseInt(param);
            int value = mCamera.getParameters().getZoom() + action;
            if (action > 0) {
                value = Math.min(mCamera.getParameters().getMaxZoom(), value);
            } else {
                value = Math.max(0, value);
            }
            mCamera.startSmoothZoom(value);
        }
        log("CAMERA_ZOOM  " + param);
        Toast.makeText(this, "CAMERA_ZOOM:" + param, Toast.LENGTH_SHORT).show();
    }

    private void onCameraRotate(String param) {
        log("CAMERA_ROTATE  " + param);
        Toast.makeText(this, "CAMERA_ROTATE:" + param, Toast.LENGTH_SHORT).show();
    }

    private void onSetRate(String param) {
        String[] split = param.split("\\*");

        int w = Integer.parseInt(split[0]);
        int h = Integer.parseInt(split[1]);

        if (publishUtil.isPushingRtmp()) {
            publishUtil.stopPush();
            publishUtil.switchResolution(w, h);
            publishUtil.startPush();
        } else {
            if (currentFragment != null) {
                stopPlay();
                startPlay(lastPlayingUrl);
            }
        }
    }

    private void setName(String name) {
        changeStatusView(1, name);
        getSharedPreferences("config", MODE_PRIVATE).edit().putString("name", name).apply();
    }

    private void showName() {
        String localnmae = getSharedPreferences("config", MODE_PRIVATE).getString("name", "");
        if (localnmae != null && !(localnmae.trim().isEmpty())) {
            currentCameraName = localnmae.trim();
            changeStatusView(1, currentCameraName);
        }
    }


    private void changeStatusView(int status, String msg) {
        //status  0:warnig   1:success   2:error
        Drawable drawable = null;
        if (status == 0) {
            drawable = getResources().getDrawable(R.drawable.orange_circle);
        } else if (status == 1) {
            drawable = getResources().getDrawable(R.drawable.orange_green);
        } else if (status == 2) {
            drawable = getResources().getDrawable(R.drawable.orange_red);
        }

        statusView.setBackground(drawable);
        statusTv.setText(msg);
    }


    private void stopPush() {
        showHideUiViews(View.VISIBLE);
        publishUtil.stopPush();
    }


    private void startPush(String pushUrl) {
        showHideUiViews(View.GONE);

        if (publishUtil.isPushingRtmp()) {
            return;
        }
        publishUtil.setPublishUrl("rtmp://" + Constants.HOST + pushUrl);
        mCamera.startPreview();
        publishUtil.startPush();

//        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
//        PublisherFragment publisherFragment = new PublisherFragment();
//        currentFragment = publisherFragment;
//        Bundle args = new Bundle();
//        args.putString("url", pushUrl);
//        publisherFragment.setArguments(args);
//        fragmentTransaction.replace(fragContainer.getId(), publisherFragment);
//        fragmentTransaction.commit();
    }

    @Override
    protected void onPause() {
        System.out.println("######   onPause");
        if (mCamera != null) {
            mCamera.stopPreview();
        }
        super.onPause();
    }

    @Override
    protected void onResume() {
        System.out.println("######   onResume");
        super.onResume();
        try {
            if (mCamera != null) {
                mCamera.startPreview();
            }
        } catch (Exception e) {
        }
    }

    private void startPlay(String playUrl) {
        System.out.println("#########  开始拉流 " + playUrl);
        lastPlayingUrl = playUrl;
        mCamera.stopPreview();
        stopPush();
        if (currentFragment != null) {
            return;
        }
        mSurfaceView.setVisibility(View.GONE);
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        if (playUrl.startsWith("rtsp")) {
            currentFragment = new RtspPlayerFragment();
        } else {
            currentFragment = new PlayerFragment();
        }
        Bundle args = new Bundle();
        args.putString("url", playUrl);
        currentFragment.setArguments(args);
        fragmentTransaction.replace(R.id.frag_container, currentFragment);
        fragmentTransaction.commit();
    }

    private void showHideUiViews(int visible) {
        statusParent.setVisibility(visible);
        btnsParent.setVisibility(visible);
    }

    public void stopPlay() {
        if (currentFragment == null) return;
        mSurfaceView.setVisibility(View.VISIBLE);

        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        fragmentTransaction.remove(currentFragment);
        fragmentTransaction.commit();

        currentFragment = null;

        mCamera.startPreview();


    }


    private void log(String s) {
        System.out.println("########   " + s);
    }

    @Override
    protected void onDestroy() {
        log("ActivityDestroy !!!");

        ServiceManager.stopService(this);

        EventBus.getDefault().unregister(this);

        publishUtil.onDestroy();
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
        mSurfaceView = null;
        mSurfaceHolder = null;

        super.onDestroy();
    }


    //--------------------------------  CAMERA  --------------------------------//
    private static String TAG = "##########";
    private PublishUtil publishUtil;
    private SurfaceView mSurfaceView = null;
    private SurfaceHolder mSurfaceHolder = null;
    private boolean mPreviewRunning = false; //priview状态
    private Camera mCamera = null;
    private Camera.AutoFocusCallback myAutoFocusCallback = null;    //自动对焦
    private static final int FRONT = 1;        //前置摄像头标记
    private static final int BACK = 2;        //后置摄像头标记
    private int currentCameraType = BACK;    //当前打开的摄像头标记
    private int curCameraIndex = -1;

    private static final int PORTRAIT = 1;    //竖屏
    private static final int LANDSCAPE = 2;    //横屏 home键在右边的情况
    private static final int LANDSCAPE_LEFT_HOME_KEY = 3; // 横屏 home键在左边的情况
    private int currentOrigentation = PORTRAIT;
    private int frameCount = 0;


    /*it will call when surfaceChanged*/
    private void initCamera(SurfaceHolder holder) {
        Log.i(TAG, "initCamera..");
        if (mPreviewRunning)
            mCamera.stopPreview();
        Camera.Parameters parameters;
        try {
            parameters = mCamera.getParameters();
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        int videoWidth = publishUtil.getVideoWidth();
        int videoHeight = publishUtil.getVideoHeight();

        parameters.setPreviewSize(videoWidth, videoHeight);
        parameters.setPictureFormat(PixelFormat.JPEG);
        parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);

        publishUtil.SetCameraFPS(parameters);

        publishUtil.setCameraDisplayOrientation(this, curCameraIndex, mCamera);

        mCamera.setParameters(parameters);

        int bufferSize = (((videoWidth | 0xf) + 1) * videoHeight * ImageFormat.getBitsPerPixel(parameters.getPreviewFormat())) / 8;

        mCamera.addCallbackBuffer(new byte[bufferSize]);

        mCamera.setPreviewCallbackWithBuffer(this);
        try {
            mCamera.setPreviewDisplay(holder);
        } catch (Exception ex) {
            if (null != mCamera) {
                mCamera.release();
                mCamera = null;
            }
            ex.printStackTrace();
        }
        mCamera.startPreview();
        mCamera.autoFocus(myAutoFocusCallback);
        mPreviewRunning = true;
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.i(TAG, "surfaceCreated ");
        System.out.println("######   surfaceCreated");
        try {
            currentCameraType = FRONT;
            if (mCamera == null) {
                mCamera = openCamera(currentCameraType);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.i(TAG, "surfaceChanged..");
        System.out.println("######   surfaceChanged");
        initCamera(holder);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.i(TAG, "Surface Destroyed");
    }

    public void onConfigurationChanged(Configuration newConfig) {
        try {
            super.onConfigurationChanged(newConfig);
            Log.i(TAG, "onConfigurationChanged");
            if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
                if (!publishUtil.isPushingRtmp()) {
                    int rotation = getWindowManager().getDefaultDisplay().getRotation();
                    if (Surface.ROTATION_270 == rotation) {
                        Log.i(TAG, "onConfigurationChanged rotation=" + rotation + " LANDSCAPE_LEFT_HOME_KEY");

                        currentOrigentation = LANDSCAPE_LEFT_HOME_KEY;
                    } else {
                        Log.i(TAG, "onConfigurationChanged rotation=" + rotation + " LANDSCAPE");

                        currentOrigentation = LANDSCAPE;
                    }
                }
            } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
                if (!publishUtil.isPushingRtmp()) {
                    currentOrigentation = PORTRAIT;
                }
            }
        } catch (Exception ex) {
        }
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        frameCount++;
        if (frameCount % 3000 == 0) {
            Log.i("OnPre", "gc+");
            System.gc();
            Log.i("OnPre", "gc-");
        }

        if (data == null) {
            Camera.Parameters params = camera.getParameters();
            Camera.Size size = params.getPreviewSize();
            int bufferSize = (((size.width | 0x1f) + 1) * size.height * ImageFormat.getBitsPerPixel(params.getPreviewFormat())) / 8;
            camera.addCallbackBuffer(new byte[bufferSize]);
        } else {
            if (publishUtil.isPushingRtmp()) {
                publishUtil.SmartPublisherOnCaptureVideoData(data, currentCameraType, currentOrigentation);
            }
            camera.addCallbackBuffer(data);
        }
    }

    @SuppressLint("NewApi")
    private Camera openCamera(int type) {
        int frontIndex = -1;
        int backIndex = -1;
        int cameraCount = Camera.getNumberOfCameras();
        Log.i(TAG, "cameraCount: " + cameraCount);

        Camera.CameraInfo info = new Camera.CameraInfo();
        for (int cameraIndex = 0; cameraIndex < cameraCount; cameraIndex++) {
            Camera.getCameraInfo(cameraIndex, info);

            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                frontIndex = cameraIndex;
            } else if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                backIndex = cameraIndex;
            }
        }

        currentCameraType = type;
        if (type == FRONT && frontIndex != -1) {
            curCameraIndex = frontIndex;
            return Camera.open(frontIndex);
        } else if (type == BACK && backIndex != -1) {
            curCameraIndex = backIndex;
            return Camera.open(backIndex);
        }
        return null;
    }

    private void switchCamera() throws IOException {
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mCamera.release();

        if (currentCameraType == FRONT) {
            mCamera = openCamera(BACK);
        } else if (currentCameraType == BACK) {
            mCamera = openCamera(FRONT);
        }
        initCamera(mSurfaceHolder);
    }

    //--------------------------------  CAMERA  --------------------------------//


    @Override
    public void onBackPressed() {

    }
}
